using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
using System.Collections;
using MageDefender.ParticleEngine;
using MageDefender.Interfaces;


namespace MageDefender.GameObjects
{
    /// <summary>
    /// This is a game component that implements IUpdateable.
    /// </summary>
    public class SpellHandler : Microsoft.Xna.Framework.DrawableGameComponent, Interfaces.ISpellHandler
    {
        public enum Spells { Fireball = 1, Slowball = 2, PoisonBall, MagicMissile, EnergyBall, MagicMissileX2, MagicMissileX4 };

        SpriteBatch spriteBatch;

        ParticleSystem killEnemyParticles;

        List<GameClasses.GameModel> spellModels;
        List<GameClasses.Spell> spells;
        List<GameClasses.Spell> spellReference;

        AudioEngine engine;
        SoundBank soundBank;
        WaveBank waveBank;
        Cue collideCue;

        public List<GameClasses.Spell> SpellReference
        {
            get { return spellReference; }
            set { spellReference = value; }
        }

        List<GameObjects.SpellHandler.Spells> learnedSpells;

        public List<GameObjects.SpellHandler.Spells> LearnedSpells
        {
            get { return learnedSpells; }
            set { learnedSpells = value; }
        }

        public void ClearSpellList()
        {
            spells.Clear();
        }

        public List<GameClasses.Spell> SpellList
        {
            get { return spells; }
            set { spells = value; }
        }

        GameObjects.SpellHandler.Spells selectedSpell = Spells.Fireball;
        int numberOfSpells = 0;

        public int NumberOfSpells
        {
            get { return numberOfSpells; }
            set { numberOfSpells = value; }
        }

        public GameObjects.SpellHandler.Spells SelectedSpell
        {
            get { return selectedSpell; }
            set { selectedSpell = value; }
        }

        int selectedSpellIndex = 0;

        public int SelectedSpellIndex
        {
            get { return selectedSpellIndex; }
            set { selectedSpellIndex = value; }
        }

        private void GenerateSpells()
        {
            GameClasses.GameModel fireballModel = new GameClasses.GameModel(this.Game);
            fireballModel.SetFileProperties("Models\\fireball", "Textures\\spell1", "Textures\\Toon");
            numberOfSpells++;
            spellModels.Add(fireballModel);

            GameClasses.GameModel test1Model = new GameClasses.GameModel(this.Game);
            test1Model.SetFileProperties("Models\\spikeball01", "Textures\\spell2", "Textures\\Toon");
            numberOfSpells++;
            spellModels.Add(test1Model);

            GameClasses.GameModel test2Model = new GameClasses.GameModel(this.Game);
            test2Model.SetFileProperties("Models\\poison_ball", "Textures\\fly3", "Textures\\Toon");
            numberOfSpells++;
            spellModels.Add(test2Model);

            GameClasses.GameModel test3Model = new GameClasses.GameModel(this.Game);
            test3Model.SetFileProperties("Models\\spikeball03", "Textures\\magicmissile", "Textures\\Toon");
            numberOfSpells++;
            spellModels.Add(test3Model);



            // Add one of each spell

            GameClasses.Spell fireballSpell = new GameClasses.Spell(Spells.Fireball, GameClasses.Spell.Alignments.Damage, 0, 1, 10, 1, 3, false, 100, new Vector3(0), 0, "Deals damage|Starter spell");
            spellReference.Add(fireballSpell);

            GameClasses.Spell test1Spell = new GameClasses.Spell(Spells.Slowball, GameClasses.Spell.Alignments.Slow, 1, 3, 20, 2, 2, false, 100, new Vector3(0), 1000, "Slows the enemy by|50 % pr. hit");
            spellReference.Add(test1Spell);

            GameClasses.Spell test2Spell = new GameClasses.Spell(Spells.PoisonBall, GameClasses.Spell.Alignments.Poison, 2, 5, 30, 3, 3, false, 100, new Vector3(0), 2000, "Poisons the enemy.|Damage over time");
            spellReference.Add(test2Spell);

            GameClasses.Spell test3Spell = new GameClasses.Spell(Spells.MagicMissile, GameClasses.Spell.Alignments.Damage, 3, 10, 40, 6, 4, false, 100, new Vector3(0), 3000, "Moderate damage.|Homing: Random enemy");
            spellReference.Add(test3Spell);

            GameClasses.Spell energySpell = new GameClasses.Spell(Spells.EnergyBall, GameClasses.Spell.Alignments.Damage, 3, 20, 40, 8, 0.6f, true, 200, new Vector3(0), 4000, "Damage while touching.|Controllable: R-stick");
            spellReference.Add(energySpell);

            GameClasses.Spell mm2Spell = new GameClasses.Spell(Spells.MagicMissileX2, GameClasses.Spell.Alignments.Damage, 3, 10, 20, 10, 4, false, 100, new Vector3(0), 5000, "2 Magic Missiles.|Homing: Random enemy");
            spellReference.Add(mm2Spell);

            GameClasses.Spell mm4Spell = new GameClasses.Spell(Spells.MagicMissileX4, GameClasses.Spell.Alignments.Damage, 3, 10, 10, 12, 4, false, 100, new Vector3(0), 6000, "4 Magic Missiles.|Homing: Random enemy");
            spellReference.Add(mm4Spell);


            // Start with the following spells
            learnedSpells.Add(Spells.Fireball);

        }

        public int GetManaCost(Spells spellType)
        {
            int returnValue = 0;
            foreach (GameClasses.Spell s in spellReference)
            {
                if (s.Type == spellType)
                {
                    returnValue = s.Mana;
                }
            }
            return returnValue;
        }

        public int GetSpellPrice(Spells spellType)
        {
            int returnValue = 0;
            foreach (GameClasses.Spell s in spellReference)
            {
                if (s.Type == spellType)
                {
                    returnValue = s.Price;
                }
            }
            return returnValue;
        }
        public string GetSpellDescription(Spells spellType)
        {
            string returnValue = "";
            foreach (GameClasses.Spell s in spellReference)
            {
                if (s.Type == spellType)
                {
                    returnValue = s.Description;
                }
            }
            return returnValue;
        }

        public void AddSpell(Vector3 pos, Spells s, Vector3 target)
        {
            pos.Y += 300;
            pos.Z += 100;

            switch (s)
            {
                case Spells.Fireball:
                {
                    GameClasses.Spell fireballSpell = new GameClasses.Spell(Spells.Fireball, GameClasses.Spell.Alignments.Damage, 0, 1, 10, 1, 3, false, 100, pos, 0, "Deals damage|Starter spell");
                    spells.Add(fireballSpell);

                    break;
                }
                case Spells.Slowball:
                {
                    GameClasses.Spell test1Spell = new GameClasses.Spell(Spells.Slowball, GameClasses.Spell.Alignments.Slow, 1, 3, 20, 2, 2, false, 100, pos, 1000, "Slows the enemy by|50 % pr. hit");
                    spells.Add(test1Spell);

                    break;
                }
                case Spells.PoisonBall:
                {
                    GameClasses.Spell test2Spell = new GameClasses.Spell(Spells.PoisonBall, GameClasses.Spell.Alignments.Poison, 2, 5, 30, 3, 3, false, 100, pos, 2000, "Poisons the enemy.|Damage over time");
                    spells.Add(test2Spell);

                    break;
                }
                case Spells.MagicMissile:
                {
                    GameClasses.Spell test3Spell = new GameClasses.Spell(Spells.MagicMissile, GameClasses.Spell.Alignments.Damage, 3, 10, 40, 6, 4, false, 100, pos, 3000, "Moderate damage.|Homing: Random enemy");
                    test3Spell.Target = target;
                    spells.Add(test3Spell);

                    break;
                }
                case Spells.EnergyBall:
                {
                    GameClasses.Spell energySpell = new GameClasses.Spell(Spells.EnergyBall, GameClasses.Spell.Alignments.Damage, 3, 20, 40, 8, 0.6f, true, 200, pos, 4000, "Damage while touching.|Controllable: R-stick");
                    spells.Add(energySpell);

                    break;
                }
                case Spells.MagicMissileX2:
                {
                    GameClasses.Spell mm2Spell = new GameClasses.Spell(Spells.MagicMissileX2, GameClasses.Spell.Alignments.Damage, 3, 10, 20, 10, 4, false, 100, pos, 5000, "2 Magic Missiles.|Homing: Random enemy");
                    mm2Spell.Target = target;
                    spells.Add(mm2Spell);

                    break;
                }
                case Spells.MagicMissileX4:
                {
                    GameClasses.Spell mm4Spell = new GameClasses.Spell(Spells.MagicMissileX4, GameClasses.Spell.Alignments.Damage, 3, 10, 10, 12, 4, false, 100, pos, 6000, "4 Magic Missiles.|Homing: Random enemy");
                    mm4Spell.Target = target;
                    spells.Add(mm4Spell);

                    break;
                }
            }
        }

        public void LearnSpell(SpellHandler.Spells learn)
        {
            learnedSpells.Add(learn);
        }

        public SpellHandler(Game game)
            : base(game)
        {
            // TODO: Construct any child components here
            engine = new AudioEngine("Content\\music.xgs");
            soundBank = new SoundBank(engine, "Content\\SoundBank.xsb");
            waveBank = new WaveBank(engine, "Content\\WaveBank.xwb");

            collideCue = soundBank.GetCue("collide");

            spellModels = new List<GameClasses.GameModel>();
            spells = new List<GameClasses.Spell>();
            spellReference = new List<GameClasses.Spell>();
            learnedSpells = new List<SpellHandler.Spells>();


            killEnemyParticles = new SpellExplosionParticleSystem(game, game.Content);
            
            GenerateSpells();
        }

        /// <summary>
        /// Allows the game component to perform any initialization it needs to before starting
        /// to run.  This is where it can query for any required services and load content.
        /// </summary>
        public void Initialize(Matrix projMatrix, Matrix viewMatrix)
        {
            // TODO: Add your initialization code here
            //sceneryModel.Initialize("Models\\plane", "Models\\grass_tex", "Models\\grass_tex", projMatrix, viewMatrix);
            foreach (GameClasses.GameModel m in spellModels)
            {
                m.Initialize(projMatrix, viewMatrix);
            }

            killEnemyParticles.Initialize();

            base.Initialize();
        }

        protected override void LoadContent()
        {
            spriteBatch = new SpriteBatch(GraphicsDevice);

            base.LoadContent();
        }

        /// <summary>
        /// Allows the game component to update itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        public void Update(GameTime gameTime, Vector3 vecEye, Matrix viewMatrix, Matrix projMatrix)
        {
            engine.Update();

            // TODO: Add your update code here
            IPlayer player = (IPlayer)Game.Services.GetService(typeof(IPlayer));

            int itemsToDelete = 0;
            foreach (GameClasses.Spell s in spells)
            {
                GamePadState playerState = GamePad.GetState(player.PlayerIndexSaved);

                if (s.Active)
                {
                    switch (s.Type)
                    {
                        case Spells.Fireball:
                            {
                                s.PositionZ += s.Speed * (gameTime.ElapsedGameTime.Milliseconds);
                                s.Update(vecEye, viewMatrix);
                                break;
                            }
                        case Spells.Slowball:
                        {
                            s.PositionZ += s.Speed * (gameTime.ElapsedGameTime.Milliseconds);
                            s.RotationY = s.PositionZ/500;
                            s.Update(vecEye, viewMatrix);
                            break;
                        }
                        case Spells.PoisonBall:
                        {
                            s.PositionZ += s.Speed * (gameTime.ElapsedGameTime.Milliseconds);
                            s.Update(vecEye, viewMatrix);
                            break;
                        }
                        case Spells.MagicMissile:
                        {
                            s.PositionZ += s.Speed * (gameTime.ElapsedGameTime.Milliseconds);

                            float diff = Math.Abs(s.PositionX - s.Target.X);

                            if (s.PositionX < s.Target.X)
                            {
                                s.MoveXPosToTarget += (gameTime.ElapsedGameTime.Milliseconds / 20.0f) * (diff / 1000.0f);
                            }
                            if (s.PositionX > s.Target.X)
                            {
                                s.MoveXPosToTarget -= (gameTime.ElapsedGameTime.Milliseconds / 20.0f) * (diff / 1000.0f);
                            }

                            s.PositionX += s.MoveXPosToTarget;

                            s.Update(vecEye, viewMatrix);
                            break;
                        }
                        case Spells.EnergyBall:
                        {
                            s.PositionZ += s.Speed * (gameTime.ElapsedGameTime.Milliseconds);
                            s.PositionX -= playerState.ThumbSticks.Right.X * 10;
                            s.Update(vecEye, viewMatrix);
                            break;
                        }
                        default:
                        {
                            s.PositionZ += s.Speed * (gameTime.ElapsedGameTime.Milliseconds);
                            s.Update(vecEye, viewMatrix);
                            break;
                        }
                    }
                }
                else
                {
                    itemsToDelete++;
                }
            }

            while (itemsToDelete > 0)
            {
                int index = -1;
                foreach (GameClasses.Spell s in spells)
                {
                    index++;
                    if (!s.Active)
                    {
                        for (int i = 0; i < 10; i++)
                        {
                            collideCue = soundBank.GetCue("sizzle");
                            if (!collideCue.IsPlaying)
                            {
                                collideCue.Play();
                            }
                            killEnemyParticles.AddParticle(new Vector3(s.PositionX * 0.008f, s.PositionY * 0.008f, s.PositionZ * 0.008f), Vector3.Zero);
                        }
                        break;
                    }
                }
                spells.RemoveRange(index, 1);
                itemsToDelete--;
            }

            killEnemyParticles.SetCamera(viewMatrix, projMatrix);


            killEnemyParticles.Update(gameTime);

            base.Update(gameTime);
        }

        public void DrawParticlesOnly(GameTime gameTime)
        {
            //spriteBatch.Begin(SpriteBlendMode.None, SpriteSortMode.Immediate, SaveStateMode.SaveState);
            killEnemyParticles.Draw(gameTime);
            //spriteBatch.End();

            //base.Draw(gameTime);
        }

        public void DrawWithParticles(GameTime gameTime)
        {
            spriteBatch.Begin(SpriteBlendMode.None, SpriteSortMode.Immediate, SaveStateMode.SaveState);
            killEnemyParticles.Draw(gameTime);
            spriteBatch.End();

            Draw(gameTime);
        }

        public override void Draw(GameTime gameTime)
        {
            //sceneryModel.Draw(gameTime);
            foreach (GameClasses.Spell s in spells)
            {
                if (s.Active)
                {
                    spellModels[s.ModelID].Update(s.VecEye, s.ViewMatrix, s.WorldMatrix, gameTime);
                    spellModels[s.ModelID].Draw(gameTime);
                }
            }

            base.Draw(gameTime);
        }
    }
}